package maosy.lib.http;

import maosy.lib.http.base.HttpDeleteWithBody;
import maosy.lib.http.base.HttpGetWithBody;
import maosy.lib.http.callback.HttpErrorCallback;
import maosy.lib.http.callback.HttpRespCallback;
import maosy.lib.http.exception.HttpErrorException;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class HttpClientUtils {

    private final static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);


    /**
     * post 请求 request body
     *
     * @param url  请求路径
     * @param data json data
     * @return String
     */
    public static void httpPostBody(String url, String data, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        HttpPost post = new HttpPost(url);
        post.setEntity(new StringEntity(data, "UTF-8"));
        requestBody(post, callback, errorCallback);
    }

    /**
     * HTTP put 方法
     *
     * @param url  请求路径
     * @param data json data
     * @return String
     */
    public static void httpPutBody(String url, String data, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        HttpPut put = new HttpPut(url);
        put.setEntity(new StringEntity(data, "UTF-8"));
        requestBody(put, callback, errorCallback);
    }

    public static void httpGetBody(String url, String data, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        HttpGetWithBody get = new HttpGetWithBody(url);
        get.setEntity(new StringEntity(data, "UTF-8"));
        requestBody(get, callback, errorCallback);
    }

    /**
     * delete 请求 request body
     *
     * @param url  请求路径
     * @param data json data
     * @return String
     */
    public static void httpDeleteBody(String url, String data, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        HttpDeleteWithBody delete = new HttpDeleteWithBody(url);
        if (StringUtils.isNotBlank(data)) delete.setEntity(new StringEntity(data, "UTF-8"));
        requestBody(delete, callback, errorCallback);
    }


    public static void httpPost(String url, List<NameValuePair> params, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        httpPost(url, params, null, callback, errorCallback);
    }

    public static void httpPatch(String url, List<NameValuePair> pairs, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        httpPatch(url, pairs, null, callback, errorCallback);
    }

    public static void httpGet(String url, List<NameValuePair> params, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        httpGet(url, params, null, callback, errorCallback);
    }

    public static void httpDelete(String url, List<NameValuePair> params, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        httpDelete(url, params, null, callback, errorCallback);
    }

    public static void httpPatch(String url, List<NameValuePair> pairs, List<Header> headers, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        CloseableHttpClient client = HttpClients.createDefault();
        final HttpPatch patch = new HttpPatch(url);
        if (headers != null && !headers.isEmpty()) headers.forEach(patch::addHeader);
        request(client, patch, pairs, callback, errorCallback);
    }

    public static void httpPost(String url, List<NameValuePair> params, List<Header> headers, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        CloseableHttpClient client = HttpClients.createDefault();
        final HttpPost post = new HttpPost(url);
        if (headers != null && !headers.isEmpty()) headers.forEach(post::addHeader);
        request(client, post, params, callback, errorCallback);
    }

    public static void httpDelete(String url, List<NameValuePair> params, List<Header> headers, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        CloseableHttpClient client = HttpClients.createDefault();
        final HttpDeleteWithBody delete = new HttpDeleteWithBody(url);
        if (headers != null && !headers.isEmpty()) headers.forEach(delete::addHeader);
        request(client, delete, params, callback, errorCallback);
    }

    public static void httpGet(String url, List<NameValuePair> params, List<Header> headers, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        try {
            CloseableHttpClient client = HttpClients.createDefault();
            HttpGet get = new HttpGet(appendUrl(url, params));
            if (headers != null && !headers.isEmpty()) headers.forEach(get::addHeader);
            HttpResponse response = client.execute(get);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                callback.callback(HttpStatus.SC_OK, EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
            } else {
                errorCallback.error(response.getStatusLine().getStatusCode(), new HttpErrorException(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)));
            }
        } catch (IOException e) {
            errorCallback.error(-1, e);
        }
    }

    private static String appendUrl(String url, List<NameValuePair> params) {
        final StringBuilder urlSb = new StringBuilder(url);
        if (!url.contains("?")) urlSb.append("?");
        else urlSb.append("&");
        if (params != null) {
            urlSb.append(URLEncodedUtils.format(params, "UTF-8"));
        }
        return urlSb.toString();
    }


    private static void request(HttpClient client, HttpEntityEnclosingRequestBase entityEnclosing, List<NameValuePair> pairs, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        try {
            assert entityEnclosing != null;
            entityEnclosing.setEntity(new UrlEncodedFormEntity(pairs, "UTF-8"));
            HttpResponse response = client.execute(entityEnclosing);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                callback.callback(response.getStatusLine().getStatusCode(), EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
            } else {
                errorCallback.error(response.getStatusLine().getStatusCode(), new HttpErrorException(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)));
            }
        } catch (IOException e) {
            errorCallback.error(-1, e);
        }
    }

    private static void requestBody(HttpEntityEnclosingRequestBase entityEnclosing, HttpRespCallback callback, HttpErrorCallback errorCallback) {
        try {
            entityEnclosing.setHeader("Content-Type", "application/json; charset=utf-8");
            HttpClient client = HttpClients.createDefault();
            HttpResponse response = client.execute(entityEnclosing);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK
                    || response.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED
                    || response.getStatusLine().getStatusCode() == HttpStatus.SC_RESET_CONTENT) {
                callback.callback(response.getStatusLine().getStatusCode(), EntityUtils.toString(response.getEntity(), "UTF-8"));
            } else {
                errorCallback.error(response.getStatusLine().getStatusCode(), new HttpErrorException(EntityUtils.toString(response.getEntity(), "UTF-8")));
            }
        } catch (IOException e) {
            errorCallback.error(-1, e);
        }
    }
}
